package com.xx.springsecuritydemo.main.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xx.springsecuritydemo.main.filter.LoginKaptchaFilter;
import com.xx.springsecuritydemo.main.handler.MyAuthenticationFailureHandler;
import com.xx.springsecuritydemo.main.handler.MyAuthenticationSuccessHandler;
import com.xx.springsecuritydemo.main.handler.MyLogoutSuccessHandler;
import com.xx.springsecuritydemo.main.security.CustomAccessDecisionManager;
import com.xx.springsecuritydemo.main.security.CustomSecurityMetadataSource;
import com.xx.springsecuritydemo.main.security.MyExpiredSessionStrategy;
import com.xx.springsecuritydemo.main.security.MyPersistentTokenBasedRememberMeServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
import org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy;
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 前后端分离springSecurity配置类
 */
//@Configuration
public class WebSecurityConfigurer2 extends WebSecurityConfigurerAdapter {
//    private final UserDetailsService userDetailsService;
//
//    private final CustomSecurityMetadataSource customSecurityMetadataSource;
//
//    private final CustomAccessDecisionManager customAccessDecisionManager;
//
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
//
//    @Autowired
//    public WebSecurityConfigurer2(UserDetailsService userDetailsService,
//                                  CustomSecurityMetadataSource customSecurityMetadataSource,
//                                  CustomAccessDecisionManager customAccessDecisionManager) {
//        this.customSecurityMetadataSource = customSecurityMetadataSource;
//        this.userDetailsService = userDetailsService;
//        this.customAccessDecisionManager = customAccessDecisionManager;
//    }
//
//    /**
//     * 自定义AuthenticationManager
//     *
//     * @param auth
//     * @throws Exception
//     */
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        System.out.println("⾃定义AuthenticationManager: " + auth);
//        // 使用自定义的userDetailsService
//        auth.userDetailsService(userDetailsService);
//    }
//
//    //"作⽤: ⽤来将⾃定义AuthenticationManager在⼯⼚中进⾏暴露,可以在任何位置注⼊
//    @Override
//    @Bean
//    public AuthenticationManager authenticationManagerBean() throws Exception {
//        return super.authenticationManagerBean();
//    }
//
//    @Bean
//    public RememberMeServices rememberMeServices() {
//        return new MyPersistentTokenBasedRememberMeServices(
//                UUID.randomUUID().toString(),
//                userDetailsService,
//                new InMemoryTokenRepositoryImpl()
//        );
//    }
//
//    /**
//     * 自定义了一个组合模式的会话处理类
//     *
//     * @return
//     */
//    public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
//        List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<>();
//        delegateStrategies.add(new ChangeSessionIdAuthenticationStrategy());
//        ConcurrentSessionControlAuthenticationStrategy strategy =
//                new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
//        //设置并发会话最大数
//        strategy.setMaximumSessions(1);
//        //设置当超过并发会话最大数时，禁止后来者登录-true
//        strategy.setExceptionIfMaximumExceeded(false);
//        delegateStrategies.add(strategy);
//        delegateStrategies.add(new RegisterSessionAuthenticationStrategy(sessionRegistry()));
//        return new CompositeSessionAuthenticationStrategy(delegateStrategies);
//    }
//
//    /**
//     * 这个类在SpringSecurity中被定义用于保存会话信息，上面创建自定义会话处理类时，需要传到构造器中
//     *
//     * @return
//     */
//    @Bean
//    public SessionRegistry sessionRegistry() {
//        return new SessionRegistryImpl();
//    }
//
//    /**
//     * session事件发布者
//     *
//     * @return
//     */
//    @Bean
//    public HttpSessionEventPublisher httpSessionEventPublisher() {
//        return new HttpSessionEventPublisher();
//    }
//
//    @Bean
//    public LoginKaptchaFilter loginKaptchaFilter() throws Exception {
//        LoginKaptchaFilter loginKaptchaFilter = new LoginKaptchaFilter();
//        // 1.认证 url
//        loginKaptchaFilter.setFilterProcessesUrl("/doLogin");
//        // 2.认证 接收参数
//        loginKaptchaFilter.setUsernameParameter("username");
//        loginKaptchaFilter.setPasswordParameter("password");
//        loginKaptchaFilter.setKaptchaParameter("kaptcha");
//        // 3.指定认证管理
//        loginKaptchaFilter.setAuthenticationManager(authenticationManagerBean());
//        // 指定⾃定义rememberMeService
//        loginKaptchaFilter.setRememberMeServices(rememberMeServices());
//        // 4.指定成功时处理
//        loginKaptchaFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
//        // 5.认证失败处理
//        loginKaptchaFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
//        // 指定会话管理策略，不指定会导致会话管理失效
//        loginKaptchaFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
//        return loginKaptchaFilter;
//    }
//
//    /**
//     * 自定义认证请求
//     *
//     * @param http
//     * @throws Exception
//     */
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        //该段授权代码需要放在认证后否则将会导致部分放开权限的接口也给拦住
//        ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
//        http.apply(new UrlAuthorizationConfigurer<>(applicationContext))
//                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
//                    @Override
//                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
//                        object.setSecurityMetadataSource(customSecurityMetadataSource);
//                        object.setAccessDecisionManager(customAccessDecisionManager); // 设置自定义AccessDecisionManager
//                        // setRejectPublicInvocations(true) 会导致所有公共请求（即不需要身份认证的请求）被拦截并要求认证
//                        // 检查请求是否是公开的URL（如 /yz.jpg），如果是则不设置 rejectPublicInvocations 为 true
//                        object.setRejectPublicInvocations(false);
//                        return object;
//                    }
//                });
//
//        // 配置访问权限
//        http.authorizeHttpRequests()
//                .mvcMatchers("/yz.jpg").permitAll()
//                .and()
//                .formLogin()
//                .and()
//                .rememberMe() // 开启记住我功能
//                .rememberMeServices(rememberMeServices())
//                .and()
//                .logout()
//                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
//                .logoutSuccessHandler(new MyLogoutSuccessHandler())
//                .and()
//                .csrf().disable(); // 关闭CSRF漏洞保护
//
//        // 自定义验证码过滤器
//        http.addFilterAt(loginKaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
//
//        // 配置会话管理
//        http.sessionManagement()
//                .maximumSessions(1)
//                .expiredSessionStrategy(new MyExpiredSessionStrategy());
//
//        // 放在配置的最后
//        http.exceptionHandling()
//                .authenticationEntryPoint((req, resp, ex) -> {
//                    // 自定义认证失败方法
//                    Map<String, Object> result = new HashMap<String, Object>();
//                    result.put("msg", "未认证，请登录");
//                    result.put("status", 401);
//                    resp.setContentType("application/json;charset=UTF-8");
//                    String s = new ObjectMapper().writeValueAsString(result);
//                    resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
//                    resp.getWriter().println(s);
//                })
//                .accessDeniedHandler(new AccessDeniedHandler() {
//                    @Override
//                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
//                        Map<String, Object> result = new HashMap<String, Object>();
//                        result.put("msg", "您没有权限");
//                        result.put("status", 403);
//                        response.setContentType("application/json;charset=UTF-8");
//                        String s = new ObjectMapper().writeValueAsString(result);
//                        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
//                        response.getWriter().println(s);
//                    }
//                });
//    }


}
